#pragma once

#include <iostream>
#include <cstdio>
#include <string>
#include <cstdlib>
#include <strings.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define MESSAGE_BUFFER_SIZE 1024

namespace client {
    using namespace std;

    enum {
        USAGE_ERR = 1,
        SOCKET_ERR,
        CONNECT_ERR
    };

    class TcpClient {
    private:
        int _sockfd; // 与服务端通信用的套接字
        string _server_ip; // 服务端ip
        uint16_t _server_port; // 服务端端口

    public:
        TcpClient(const string& ip, const uint16_t& port)
            : _sockfd(-1)
            , _server_ip(ip)
            , _server_port(port)
        {}

        ~TcpClient() {
            if (_sockfd >= 0) close(_sockfd);
        }

    public:
        void initClient() {
            _sockfd = socket(AF_INET, SOCK_STREAM, 0);
            if (_sockfd < 0) {
                cerr << "client socket create err!" << endl;
                exit(SOCKET_ERR);
            }

            //* 客户端创建的socket也需要绑定，但我们不主动绑定，让OS在socket被使用时自己绑定
            //* 客户端TCP通信时不需要listen监听也不需要accept接收连接请求
            //* 客户端要做的就是直接对服务端发起连接请求
        }

        void start() {
            struct sockaddr_in server;
            bzero(&server, sizeof(server));

            server.sin_family = AF_INET;
            server.sin_port = htons(_server_port);
            server.sin_addr.s_addr = inet_addr(_server_ip.c_str());

            if (connect(_sockfd, (struct sockaddr*)&server, sizeof(server)) != 0) {
                cerr << "socket build connection err!" << endl;
                exit(CONNECT_ERR);
            }
            else {
                string message;
                for (;;) {
                    cout << "please enter your message# ";
                    fflush(stdout);

                    // 向服务端发送消息
                    getline(cin, message);
                    write(_sockfd, message.c_str(), message.size());

                    // 接收来自服务端的消息
                    char buffer[MESSAGE_BUFFER_SIZE] = {};
                    ssize_t n = read(_sockfd, buffer, MESSAGE_BUFFER_SIZE - 1);
                    if (n > 0) {
                        buffer[n] = '\0';
                        cout << buffer << endl;
                    }
                    else {
                        break; // 没读到来自服务端的信息，直接退出通信
                    }
                }
            }
        }

    }; //@end class TcpClient
} //@end namespace client